// -----------------------------
// Author: 		Dhaenens Gert	
// Creation: 	2/27/2015 7:03:41 PM				
// -----------------------------

#include "CBuffer.h"

#include "CGraphicsDevice.h"

namespace Flow
{

	CBuffer::CBuffer()
		: m_HasData(false)
		, m_Type(BufferType::Unknown)
		, m_ElementSize(0)
		, m_ElementCount(0)
	{
	}

	CBuffer::~CBuffer()
	{
	}

	void CBuffer::Release()
	{
		delete this;
	}

	Bool CBuffer::Create(IGraphicsDevice* lpDevice, BufferType::Enum type, void* lpData, Size_T elementSize, Size_T elementCount)
	{
		CGraphicsDevice* lpCDevice = static_cast<CGraphicsDevice*>(lpDevice);
		ASSERT(lpCDevice);

		D3D11_BUFFER_DESC bufferDesc = {};
		bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
		bufferDesc.ByteWidth = elementSize * elementCount;
		bufferDesc.CPUAccessFlags = 0;
		bufferDesc.MiscFlags = 0;
		bufferDesc.StructureByteStride = elementSize;
		bufferDesc.Usage = D3D11_USAGE_DEFAULT;
		
		switch (type)
		{
		case BufferType::Vertex:
			bufferDesc.BindFlags |= D3D11_BIND_VERTEX_BUFFER;
			break;
		case BufferType::Index:
			bufferDesc.BindFlags |= D3D11_BIND_INDEX_BUFFER;
			break;
		case BufferType::Constant:
			bufferDesc.BindFlags |= D3D11_BIND_CONSTANT_BUFFER;
			break;
		default:
			ASSERT(false);
			break;
		}

		D3D11_SUBRESOURCE_DATA subData = {};
		subData.pSysMem = lpData;
		D3D11_SUBRESOURCE_DATA* lpSubData = (lpData) ? &subData : NULL;

		HRESULT hr = lpCDevice->GetDevice()->CreateBuffer(&bufferDesc, lpSubData, &m_Buffer);
		ASSERT(SUCCEEDED(hr));
		if (FAILED(hr))
			return false;

		D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc = {};
		viewDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
		viewDesc.Buffer.FirstElement = 0;
		viewDesc.Buffer.NumElements = elementCount;
		viewDesc.Buffer.ElementOffset = 0;
		viewDesc.Buffer.ElementWidth = elementSize;

		hr = lpCDevice->GetDevice()->CreateShaderResourceView(m_Buffer.Get(), &viewDesc, &m_ShaderView);
		ASSERT(SUCCEEDED(hr));
		if (FAILED(hr))
			return false;

		m_ElementCount = elementCount;
		m_ElementSize = elementSize;
		m_Type = type;
		m_HasData = true;

		return true;
	}

	void CBuffer::Update(IGraphicsDevice* lpDevice, void* lpData, Size_T dataSize)
	{
		ASSERT(m_HasData);
		ASSERT(dataSize == GetTotalSize());

		CGraphicsDevice* lpCDevice = static_cast<CGraphicsDevice*>(lpDevice);
		lpCDevice->GetContext()->UpdateSubresource(m_Buffer.Get(), 0, NULL, lpData, dataSize, 0);
	}

	Bool CBuffer::HasData() const
	{
		return m_HasData;
	}

	Size_T CBuffer::GetElementSize() const
	{
		return m_ElementSize;
	}

	Size_T CBuffer::GetElementCount() const
	{
		return m_ElementCount;
	}

	Size_T CBuffer::GetTotalSize() const
	{
		return (m_ElementSize * m_ElementCount);
	}

}